﻿using System;
using System.Collections.Generic;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol.Data;
using HK.Core.Utils;
using HK.Editor.Common.Protocol;
using HK.Editor.Utils;
using UnityEngine;
using HCompareOptions = HK.Core.Common.Protocol.Data.CompareOptions;

namespace HK.Editor.Common.Data
{
    /// <summary>
    /// I/O对象白名单
    /// <para>* 目标对象包含 : 文件以及文件夹</para>
    /// </summary>
    [Serializable]
    public sealed class IOWhiteList : WhiteList, IIOWhiteList
    {

#region Create

        /// <summary>
        /// 创建I/O对象白名单
        /// </summary>
        /// <param name="iBrowseOptions">浏览选项(文件/文件夹)</param>
        /// <param name="iBrowseDesc">浏览描述</param>
        /// <param name="iCompareOptions">比较选项</param>
        /// <param name="iExtensions">扩展列表</param>
        /// <returns>I/O对象白名单</returns>
        public static IOWhiteList Create(int iBrowseOptions = (int)IoBrowseOptions.All, 
            string iBrowseDesc = null, int iCompareOptions = (int)HCompareOptions.None, 
            IFileExtensions iExtensions = null)
        {
            return new IOWhiteList(iBrowseOptions, iBrowseDesc, iCompareOptions, iExtensions);
        }

#endregion

        /// <summary>
        /// 保护构造函数
        /// </summary>
        /// <param name="iBrowseOptions">浏览选项(文件/文件夹)</param>
        /// <param name="iBrowseDesc">浏览描述</param>
        /// <param name="iCompareOptions">比较选项</param>
        /// <param name="iExtensions">扩展列表</param>
        private IOWhiteList(int iBrowseOptions = (int)IoBrowseOptions.All, string iBrowseDesc = null, 
            int iCompareOptions = (int)HCompareOptions.None, IFileExtensions iExtensions = null) :
            base(iCompareOptions, iExtensions)
        {
            browseOptions = iBrowseOptions;
            BrowseDesc = iBrowseDesc;
        }
        
#region BrowseOptions

        [SerializeField]
        private int browseOptions;
        /// <summary>
        /// I/O浏览选项
        /// <para>* 文件/文件夹</para>
        /// </summary>
        public int BrowseOptions => browseOptions;
        
        /// <summary>
        /// 文件可浏览
        /// </summary>
        public bool FileBrowsable => UtilsBytes.CheckBytes(browseOptions, (int)IoBrowseOptions.File);

        /// <summary>
        /// 文件可浏览 - Only
        /// </summary>
        public bool FileBrowseOnly => FileBrowsable && !DirectoryBrowsable;
        
        /// <summary>
        /// 目录可浏览
        /// </summary>
        public bool DirectoryBrowsable => UtilsBytes.CheckBytes(browseOptions, (int)IoBrowseOptions.Directory);

        /// <summary>
        /// 目录可浏览 - Only
        /// </summary>
        public bool DirectoryBrowseOnly => !FileBrowsable && DirectoryBrowsable;

        /// <summary>
        /// 全部可浏览
        /// </summary>
        public bool AllBrowsable => UtilsBytes.CheckBytes(browseOptions, (int)IoBrowseOptions.All);

        [SerializeField] 
        private string browseDesc = null;
        /// <summary>
        /// 浏览描述
        /// </summary>
        public string BrowseDesc
        {
            get => browseDesc;
            private set => browseDesc = value;
        }
        
        /// <summary>
        /// 浏览描述
        /// </summary>
        public string[] BrowseExtensions => Extensions.BrowseExtensions;

#endregion
        
        /// <summary>
        /// 存在校验
        /// </summary>
        /// <param name="iTarget">目标对象</param>
        /// <returns>true:存在; false:不存在;</returns>
        protected override bool Exist(string iTarget)
        {
            var exist = base.Exist(iTarget);
            if (exist)
            {
                UtilsGUIEx.DisplayDialog("失败", $"目标文件已存在!\n{iTarget}", "确认");
            }
            
            return exist;
        }

        /// <summary>
        /// 追加目标对象
        /// <para>* 无效的目标对象，或者未通过过滤验证的，都将视为失败</para>
        /// </summary>
        /// <param name="iTargets">目标对象</param>
        /// <returns>成功追加数量</returns>
        public override int AddTargets(IReadOnlyList<string> iTargets)
        {
            var addedCount = base.AddTargets(iTargets);
            if (0 >= addedCount)
            {
                var descDetail = string.Empty;
                var count = iTargets.Count;

                var loopCount = Mathf.Min(10, count);
                for (var idx = 0; idx < loopCount; ++idx)
                {
                    var target = iTargets[idx];
                    if (string.IsNullOrEmpty(target)) continue;

                    descDetail = string.IsNullOrEmpty(descDetail) ? target : $"{descDetail}\n{target}";
                }

                if (3 < count)
                {
                    descDetail = $"{descDetail}\n...";
                }
                    
                UtilsGUIEx.DisplayDialog("追加失败", $"追加文件中没有一个追加成功!\n{descDetail}", "确认");
            }
            
            return addedCount;
        }

#region Filter

        /// <summary>
        /// 过滤
        /// </summary>
        /// <param name="iTarget">目标对象</param>
        /// <returns>true:通过过滤; false:未通过过滤;</returns>
        public override bool Filter(string iTarget)
        {
            var flg = false;
            if (FileBrowseOnly || FileBrowsable)
            {
                flg |= FilterFileByOptions(iTarget);
            }

            if (DirectoryBrowseOnly | DirectoryBrowsable)
            {
                flg |= FilterDirByOptions(iTarget);
            }
            
            return flg;
        }

        /// <summary>
        /// 过滤文件
        /// </summary>
        /// <param name="iTarget">目标对象</param>
        /// <returns>true:通过过滤; false:未通过过滤;</returns>
        private bool FilterFileByOptions(string iTarget)
        {
            if (string.IsNullOrEmpty(iTarget) || !System.IO.File.Exists(iTarget)) return false;
            // 校验过滤
            return Verify(iTarget);
        }
        
        /// <summary>
        /// 过滤目录
        /// </summary>
        /// <param name="iTarget">目标对象</param>
        /// <returns>true:通过过滤; false:未通过过滤;</returns>
        private bool FilterDirByOptions(string iTarget)
        {
            if (string.IsNullOrEmpty(iTarget) || !System.IO.Directory.Exists(iTarget)) return false;
            // 校验过滤
            return Verify(iTarget);
        }

#endregion

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IIOWhiteList whiteList)
            {
                browseOptions = UpdateValue(browseOptions, whiteList.BrowseOptions, iImport);
                browseDesc = UpdateValue(browseDesc, BrowseDesc, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();

            browseOptions = (int)IoBrowseOptions.All;
            browseDesc = null;
        }

    }
}
